package com.hs.hlw.credit.system.web.components;

import com.hualongdata.exception.HlBaseException;
import com.hs.hlw.credit.system.business.dto.ResponseDto;
import com.hs.hlw.credit.system.common.util.JsonUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.HttpServletRequest;

/**
 * 全局异常拦截
 * @author zhb
 * @date 2018/08/07
 */
@ControllerAdvice(basePackages = "com.hs.hlw.credit.system.web.controller")
public class GlobalExceptionHandlerAdvice extends ResponseEntityExceptionHandler {
    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
            request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
        }

        if (ex instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException exception = (MethodArgumentNotValidException) ex;
            FieldError fieldError = exception.getBindingResult().getFieldError();
            ResponseDto result = new ResponseDto(1, fieldError.getDefaultMessage());
            MultiValueMap<String, String> _headers = new LinkedMultiValueMap<>();
            _headers.set("Content-Length", JsonUtil.toJson(result).getBytes().length + "");
            return new ResponseEntity<>(result, _headers, status);
        }

        // 参数缺失异常
        if (ex instanceof MissingServletRequestParameterException) {
            logger.error("缺少请求参数", ex);
            ResponseDto result = new ResponseDto(status.value(), "缺少请求参数");
            MultiValueMap<String, String> _headers = new LinkedMultiValueMap<>();
            _headers.set("Content-Length", JsonUtil.toJson(result).getBytes().length + "");
            return new ResponseEntity<>(result, _headers, status);
        }

        logger.error("系统错误", ex);
        ResponseDto result = new ResponseDto(status.value(), "系统错误");
        MultiValueMap<String, String> _headers = new LinkedMultiValueMap<>();
        _headers.set("Content-Length", JsonUtil.toJson(result).getBytes().length + "");
        return new ResponseEntity<>(result, _headers, status);
    }


    @ExceptionHandler(RuntimeException.class)
    @ResponseBody
    ResponseEntity<Object> handleRuntimeException(HttpServletRequest request, RuntimeException ex) {
        HttpStatus status = getStatus(request);
        logger.error("运行异常", ex);
        ResponseDto result = new ResponseDto(status.value(), "运行异常");
        MultiValueMap<String, String> _headers = new LinkedMultiValueMap<>();
        _headers.set("Content-Length", JsonUtil.toJson(result).getBytes().length + "");
        return new ResponseEntity<>(result, _headers, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * 业务异常
     * @param request
     * @param ex
     * @return
     */
    @ExceptionHandler(HlBaseException.class)
    @ResponseBody
    ResponseEntity<Object> handleSBaseException(HttpServletRequest request, HlBaseException ex) {
        ResponseDto result = new ResponseDto(ex.getErrCode(), ex.getErrMsg());
        MultiValueMap<String, String> _headers = new LinkedMultiValueMap<>();
        _headers.set("Content-Length", JsonUtil.toJson(result).getBytes().length + "");
        return new ResponseEntity<>(result, _headers, HttpStatus.OK);
    }

    private HttpStatus getStatus(int statusCode) {
        for (HttpStatus status : HttpStatus.values()) {
            if (status.value() == statusCode) {
                return status;
            }
        }

        return HttpStatus.BAD_REQUEST;
    }

    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }
}
